import routes from './routes';
import store from '../store';
import pagesJson from '../pages.json';
import { isUndefined, checkToken } from '../commons/utils';

/**
 * 是否是对象
 * @param {*} options
 * @returns
 */
const isObject = options => {
    return Object.prototype.toString.call(options) === '[object Object]';
};

/**
 * 是否是字符串
 * @param {*} options
 * @returns
 */
const isString = options => {
    return Object.prototype.toString.call(options) === '[object String]';
};

/**
 * 是否为Tab页面
 * @param {*} url
 * @returns
 */
const isTab = path => {
    const ret = pagesJson.tabBar.list.some(tab => {
        return tab.pagePath === path;
    });
    return ret;
};

/**
 * 检查路由锁状态
 * @returns
 */
const checkLockStatus = () => {
    if (store.useRouteStore().lockStatus) {
        throw new Error('当前页面正在处于跳转状态，请稍后再进行跳转....');
    } else {
        return false;
    }
};

/**
 * 是否已经达到栈顶
 * @returns
 */
const isStackTop = () => {
    const pageStack = getCurrentPages();
    return pageStack >= 10;
};

/**
 * 对象转URL拼接参数
 * @param {*} obj
 * @returns
 */
const obj2query = obj => {
    let result = [];
    Object.keys(obj).forEach(key => result.push(`${key}=${obj[key]}`));
    return '?' + result.join('&');
};

/**
 * 根据名称查找路由
 * @param {*} name
 * @returns
 */
const getPathByName = name => {
    const result = routes.filter(route => {
        return route.name === name;
    });
    if (result.length === 1) {
        return result[0].path;
    } else {
        throw new Error(`[${name}] route not found`);
    }
};

/**
 * 根据URL查找路由对象
 * @param {*} name
 * @returns
 */
const getRouteByUrl = url => {
    const result = routes.filter(route => {
        return route.path === url;
    });
    if (result.length === 1) {
        return result[0];
    } else {
        throw new Error(`[${url}] route not found`);
    }
};

/**
 * 从栈内查找路由
 * @param {*} path
 * @returns
 */
const findPageInHistory = path => {
    const pageStack = getCurrentPages();
    const reg = /^\//;

    let delta = -1;

    for (let i = 0; i < pageStack.length; i++) {
        const myRoute = pageStack[i].route;
        if (myRoute && path && myRoute.replace(reg, '') === path.replace(reg, '')) {
            delta = i + 1;
            break;
        }
    }

    return delta;
};

/**
 * 普通跳转或重定向
 * @param {*} param0
 */
const redirectOrNavigateTo = (url, query, params, otherArgs, type) => {
    if (query) {
        url += query;
    } else if (params) {
        const useRouteStore = store.useRouteStore();
        useRouteStore.params = params;
    }
    if (type === 1) {
        redirectTo({ url, ...otherArgs });
    } else {
        navigateTo({ url, ...otherArgs });
    }
};

/**
 * 到达栈顶处理器
 * @param {*} param0
 */
const pageStackHandler = (url, query, params, otherArgs) => {
    const pageStack = getCurrentPages();
    const pageStackLength = pageStack.length;
    const curDelta = findPageInHistory(url);
    if (curDelta > -1) {
        navigateBack({ delta: pageStackLength - curDelta });
    } else {
        redirectOrNavigateTo(url, query, params, otherArgs, 1);
    }
};

/**
 * 用于获取params参数
 * @returns
 */
export const useRoute = () => {
    return store.useRouteStore();
};

/**
 * 返回上一页
 */
export const back = () => {
    navigateBack({ delta: 1 });
};

/**
 * 关闭当前页面，返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈，决定需要返回几层。
 * @param {*} options
 */
export const navigateBack = options => {
    if (getCurrentPages().length === 1) {
        switchTab({ url: '/pages/tabbar/home' });
    } else {
        uni.navigateBack(options);
    }
};

/**
 * 跳转到 tabBar 页面，并关闭其他所有非 tabBar 页面。
 * @param {*} options
 */
export const switchTab = options => {
    uni.switchTab(options);
};

/**
 * 关闭所有页面，打开到应用内的某个页面。
 * @param {*} options
 */
export const reLaunch = options => {
    uni.reLaunch(options);
};

/**
 * 关闭当前页面，跳转到应用内的某个页面。
 * @param {*} options
 */
export const redirectTo = options => {
    uni.redirectTo(options);
};

/**
 * 保留当前页面，跳转到应用内的某个页面，使用uni.navigateBack可以返回到原页面。
 * @param {*} options
 */
export const navigateTo = options => {
    uni.navigateTo(options);
};

/**
 * 智能路由
 * @param {*} options
 */
export const push = async options => {
    if (!isObject(options) && !isString(options)) {
        throw new Error('Parameter type error, must be object or string.');
    }
    let url = '',
        query = '',
        params = '';
    const otherArgs = {
        success: () => {},
        fail: () => {},
        complete: () => {
            store.useRouteStore().lockStatus = false;
        }
    };
    if (isObject(options)) {
        if (options.hasOwnProperty('name')) {
            url = getPathByName(options.name);
            if (options.params && isObject(options.params)) {
                params = options.params;
            }
        } else if (options.hasOwnProperty('path')) {
            url = options.path;
            if (options.query && isObject(options.query)) {
                query = obj2query(options.query);
            }
        }
        otherArgs.success = options.success ? options.success : otherArgs.success;
        otherArgs.fail = options.fail ? options.fail : otherArgs.fail;
        otherArgs.complete = options.complete ? options.complete : otherArgs.complete;
    } else if (isString(options)) {
        const idx = options.indexOf('?');
        if (idx > -1) {
            url = options.substring(0, idx);
            query = options.substring(idx, options.length);
        } else {
            url = options;
        }
    }

    /** 为即将跳转且需要token状态的页面做token是否存在检查 */
    const currentRoute = getRouteByUrl(url);
    if ((isUndefined(currentRoute.requireAuth) || currentRoute.requireAuth) && !(await checkToken())) {
        url = '/pages-user/login/index';
    }

    if (!checkLockStatus()) {
        if (isTab(url)) {
            switchTab({ url, ...otherArgs });
        } else if (isStackTop()) {
            pageStackHandler(url, query, params, otherArgs);
        } else {
            redirectOrNavigateTo(url, query, params, otherArgs, 0);
        }
    }
};

export default {
    push,
    back,
    useRoute,
    navigateTo,
    redirectTo,
    switchTab,
    reLaunch,
    navigateBack
};
